#ifndef _xMappingTree_H_
#define	_xMappingTree_H_

#include <string>
#include <vector>
#include <map>

class xLink;
class xNodeType;
class xOutMappingPort ;
class xInMappingPort ;
class xMappingNode ;
class xNodeType_VM;
class DIVA_VM;
class WOP_Entry;

class xMappingTree {

private:
	std::vector< xMappingNode * > _nodes ;
	std::vector< xMappingNode * > inputTerminals_;
	std::vector< xMappingNode * > outputTerminals_;
	std::vector< xLink * > _links ;
	int _maxlevel ;
	std::vector< std::pair< WOP_Entry *, DIVA_VM * > > wop_vm_pairs_;
	std::map< xMappingNode *, DIVA_VM * > gate_vm_table_;
	
public:
	xMappingTree();

	void update() ; // called when the values or VM of the xMappingNodes needed to be updated

	/** create a new empty mapping node in the xMappingTree, if this mapping node is a WOP or GATE, please set is_terminal as true */
	xMappingNode * create_node(xNodeType *nd_type) ;  

	///** create a new mapping node by a vmdescriptor */
	//xMappingNode * create_node(vmdescriptor *vd) ;
	///** create a new mapping node by a VM id */
	//xMappingNode * create_node(int vmid) { return create_node(vmLibrary::getInstance()->get_vmdescriptor(vmid)) ; }

	/** remove a mapping node from the tree */
	void delete_node(xMappingNode *p);

	bool verify_link(xOutMappingPort *left, xInMappingPort *right);

	/** make a connection between ports*/
	xLink *create_link(xOutMappingPort *left, xInMappingPort *right);

	/** make a connection between node and port */
	xLink *create_link(xMappingNode *leftnode, int outportindex, xInMappingPort *right);

	
	/** make a connection from a leftnode to the i-th port of rightnode */
	xLink *create_link(xMappingNode *leftnode, int outportindex, xMappingNode *rightnode, int inportindex) ;

	/** delete a link from the tree */
	void delete_link(xLink *p) ;

	/** delete all links for a xOutMappingPort */
	void delete_links(xOutMappingPort *op);

	/** add a mapping node as a terminal node. Usually, the mapping node is a WOP or gate */
	void add_input_terminal(xMappingNode *p);

	/** delete a mapping node from terminal. Usually, the mapping node is a WOP or gate, added by howway*/
	void delete_input_terminal(xMappingNode *p);

	/**
	 * @brief add a mapping node as a output terminal node.
	 *
	 * Usually, the mapping node is a WOP or gate.
	 */
	void add_output_terminal( xMappingNode * p );

	/**
	 * @brief delete a mapping node from terminal.
	 *
	 * Usually, the mapping node is a WOP or gate.
	 */
	void delete_output_terminal( xMappingNode * p );

	/** return the terminal mapping nodes */
	const std::vector<xMappingNode *> & get_input_terminals() const;

	/**
	 * @brief return the terminal mapping nodes
	 */
	const std::vector< xMappingNode * > & get_output_terminals() const;

	/**
	 * @brief get exactly output gates
	 */
	std::vector< xMappingNode * > get_output_nodes() const;

	std::vector<xLink*> getLinks(){return _links;}

	/** return a vector of all the nodes */
	std::vector<xMappingNode*> get_nodes() { return _nodes ; }

	/** given a level ID, this method returns a vector which contains the mapping nodes of that level */
	std::vector<xMappingNode*> get_nodes_by_level(int id);

	/** return a vector of all the links */
	std::vector<xLink*> get_links() { return _links ; }

	/** this method order the tree and assign a level ID to each mapping node. WVnodes are level 0 */
	void compute_level() ;

	int get_max_level() { return _maxlevel ; }

	/** add a subtree to this mapping tree, the subtree is added to the mapping node attached 
	    at inport indexed by inport_index */
	void add_tree(xMappingTree me, xMappingNode * attached, int inport_index); 
	void add_tree(xMappingTree*);

	/** given a mapping node p, this method return all the child mapping nodes which has link to p */
	static std::vector<xMappingNode*>  xMappingTree::getChildNodes(xMappingNode *p); 

	/** given a mapping node p, this method return all the parent mapping nodes which has link to p */
	static std::vector<xMappingNode*>  xMappingTree::getParentNodes(xMappingNode *p);

	/** generate a Mapping Description String for this xMappingTree */
	std::string toMDString(); 

	/** given a mapping tree, this method produce a DES file that describe the composite VM */
	std::string toCompositeDEString(std::string idname, std::string type, std::string description);

	/**
	 * produces a Type Mapping String.
	 * @param ns distingush same type name between applications
	 * @param type maps to which type
	 * @param description description of this type
	 */
	std::string toTMString( const std::string & ns, const std::string & type, const std::string & description );

	const std::vector< std::pair< WOP_Entry *, DIVA_VM * > > & get_wop_vm_pairs() const;
	DIVA_VM * get_vm_by_gate( xMappingNode * gateNode ) const;
	void collect_wop_vm_pairs();

	void saveToDESfile(std::string filename,std::string desstring,bool isModified=false);
	/** Given a MDS (Mapping Description String) and a WOP_Entry (waited to be visualized), 
	    this method construct a xMappingTree according to MDS. All wop mapping nodes are setup 
		automatically (by compare wop's vartype and name). */
	static xMappingTree* fromMDStoXMappingTree(std::string MDS, WOP_Entry *en) ;
	void clearUnusedWOP();

private:
	void find_level0_nodes() ;
	void find_level1_nodes() ;
	int  maxlevel_of_childs(xMappingNode * p) ;
	static void set_vm_default_values(xNodeType_VM *vm, int inport_no, std::vector<std::string> tokens, int index_of_token);
	std::string printIndent(int);
	void resetMDSFlag();
};

#endif
